package lumis.portal.page;

import lumis.portal.PortalException;
import lumis.portal.PortalObjectAlreadyExistsException;
import lumis.portal.PortalObjectNotFoundException;
import lumis.portal.UnexpectedException;
import lumis.portal.channel.tree.GenericChannelChild;
import lumis.portal.channel.tree.IChannelChild;
import lumis.portal.channel.tree.IChannelChildProvider;
import lumis.portal.dao.DaoException;
import lumis.portal.dao.hibernate.GenericHibernateManualUpdateDao;
import lumis.portal.dao.hibernate.ITransactionHibernate;
import lumis.portal.dao.jdbc.ITransactionJdbc;
import lumis.portal.localization.ILocalizationManager;
import lumis.portal.manager.ManagerFactory;
import lumis.util.*;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import org.hibernate.Session;

/**
 * @version $Revision: 12074 $ $Date: 2010-11-05 21:36:31 -0200 (Fri, 05 Nov 2010) $
 * @since 4.0.0
 */
public class PageDaoHib extends GenericHibernateManualUpdateDao<PageConfig, String> implements IPageDao
{
	public PageDaoHib()
	{
		super(PageConfig.class);
	}	
		
	protected String getIdentifier(PageConfig bean)
	{
		return bean.getId();
	}
	
	public PageConfig get(String pageId, ITransaction transaction) throws PortalException
	{
		PageConfig pageConfig = super.get(pageId, transaction);
		if (pageConfig.getLayout() == null)
			pageConfig.setLayout(autoGenerateLayout(pageConfig, transaction));
		return pageConfig;
	}
	
	public PageConfig getCommitted(String pageId, ITransaction transaction) throws PortalException
	{
		// evict the pageConfig from the transaction's session
		ITransactionHibernate txHib = (ITransactionHibernate)transaction;
		Session session = txHib.getSession();
		PageConfig pageConfig = (PageConfig)session.get(PageConfig.class, pageId);
		session.evict(pageConfig);

		// read the pageConfig config again
		return get(pageId, transaction);
	}

	public void add(PageConfig pageConfig, ITransaction transaction) throws DaoException, PortalException
	{
		super.add(pageConfig, transaction);
	}

	public boolean delete(String pageId, ITransaction transaction) throws DaoException, PortalException
	{
		return super.delete(pageId, transaction);
	}

	public void update(PageConfig pageConfig, ITransaction transaction) throws DaoException, PortalException
	{
		super.update(pageConfig, transaction);
		
		// evict the page from the session, to prevent dirty propertyBagId 
		// (not updatable) from being stored in the session's persistence context 
		ITransactionHibernate txHib = (ITransactionHibernate)transaction; 
		Session session = txHib.getSession(); 
		session.evict(session.load(PageConfig.class, pageConfig.getId()));  
	}
	
	@Override
	public void evict(String pageId, ITransaction transaction) throws PortalException
	{
		super.evict(pageId, transaction);
	}
	
	private String autoGenerateLayout(PageConfig pageConfig, ITransaction daoTransaction) throws DaoException, PortalException
	{
		try
		{
			String layout = null;

			layout = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
			layout += "<layout><area><column width=\"100%\">";

			if(pageConfig.getType() == PageConfig.PAGE_TYPE_ADMIN)
			{
				String strQuery = "SELECT interfaceInstanceId FROM lum_InterfaceInstance WHERE pageId=? and isCreatedRunTime = 0";
	
				ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) daoTransaction;
				Connection connection = daoTransactionJdbc.getConnection();
				PreparedStatement statement = connection.prepareStatement(strQuery);
				try
				{
					statement.setString(1, pageConfig.getId());
					ResultSet resultSet = statement.executeQuery();
					try
					{
						String interfaceInstanceId;
	
						while (resultSet.next())
						{
							interfaceInstanceId = resultSet.getString("interfaceInstanceId");
							layout += "<row><cell>" + interfaceInstanceId + "</cell></row>";
						}
					}
					finally
					{
						resultSet.close();
					}
				}
				finally
				{
					statement.close();
				}
			}

			layout += "</column></area></layout>";

			return layout;
		}
		/*
		 * catch(PortalException e) { throw e; }
		 */
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public String getFirstIdByChannelId(String channelId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			String pageId = null;
			String strQuery = "SELECT pageId FROM lum_Page WHERE channelId=? and isTemplate=0 order by position asc, name asc";

			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement(strQuery);
			try
			{
				statement.setString(1, channelId);
				ResultSet resultSet = statement.executeQuery();
				try
				{
					if (resultSet.next())
						pageId = resultSet.getString("pageId");
				}
				finally
				{
					resultSet.close();
				}
			}
			finally
			{
				statement.close();
			}

			if (pageId == null)
				throw new PortalObjectNotFoundException("STR_CHANNEL_WITHOUT_PAGES;" + channelId);

			return pageId;
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public String getIdByUserId(String userId, ITransaction transaction) throws DaoException, PortalException
	{
		return null;
	}

	public List<String> getIdsByChannelId(String channelId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("select pageId from lum_Page where channelId = ? order by position, name");
			try
			{
				statement.setString(1, channelId);

				List<String> returnValues = JdbcUtil.fillListString(statement, "pageId");				
				return returnValues;
			}
			finally
			{				
				statement.close();
			}
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public Collection<String> getIdsByParentTemplateId(String parentTemplateId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("select pageId from lum_Page where parentTemplateId = ?");
			try
			{
				statement.setString(1, parentTemplateId);

				Collection<String> returnValues = JdbcUtil.fillListString(statement, "pageId");
				return returnValues;				
			}
			finally
			{
				statement.close();
			}
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public Collection<String> getIdsByServiceInstanceId(String serviceInstanceId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("select distinct pageId from lum_InterfaceInstance where serviceInstanceId = ? AND isCreatedRunTime=0");
			try
			{
				statement.setString(1, serviceInstanceId);
				Collection<String> returnValues = JdbcUtil.fillListString(statement, "pageId");
				return returnValues;
			}
			finally
			{
				statement.close();
			}
		}
		catch (SQLException e)
		{
			throw new UnexpectedException(e);
		}
	}
	
	public boolean hasDependentPages(String pageTemplateId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("select pageId from lum_Page where parentTemplateId = ?");
			try
			{
				statement.setString(1, pageTemplateId);
				statement.setMaxRows(1);
	
				ResultSet resultSet = statement.executeQuery();

				boolean returnValue = resultSet.next();

				resultSet.close();

				return returnValue;
			}
			finally
			{
				statement.close();
			}
			
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public void addCss(String pageId, String cssId, int position, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("UPDATE lum_PageCss SET position = ?  WHERE pageId = ? AND cssId = ?");
			int rowsAffected = 0;
			try
			{
				statement.setInt(1, position);
				statement.setString(2, pageId);
				statement.setString(3, cssId);
				rowsAffected = statement.executeUpdate();
			}
			finally
			{
				statement.close();
			}

			if (rowsAffected <= 0)
			{
				statement = connection.prepareStatement("insert into lum_PageCss (pageId, cssId, position) values (?, ?, ?)");
				try
				{
					statement.setString(1, pageId);
					statement.setString(2, cssId);
					statement.setInt(3, position);
					try
					{
						statement.executeUpdate();
					}
					catch (Exception e)
					{
						try
						{
							Collection<String> cssIds = getCssIds(pageId, transaction);
							if (cssIds.contains(cssId))
								throw new PortalObjectAlreadyExistsException("STR_RESOURCE_ALREADY_EXISTS;" + cssId, e);
						}
						catch (PortalObjectNotFoundException e1)
						{
							throw e;
						}
					}
				}
				finally
				{
					statement.close();
				}
			}

		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public void deleteCss(String pageId, String cssId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("DELETE FROM lum_PageCss WHERE pageId = ? AND cssId = ?");
			try
			{
				statement.setString(1, pageId);
				statement.setString(2, cssId);
				statement.executeUpdate();
			}
			finally
			{
				statement.close();
			}
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public List<String> getCssIds(String pageId, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
			Connection connection = daoTransactionJdbc.getConnection();

			PreparedStatement statement = connection.prepareStatement("SELECT cssId FROM lum_PageCss WHERE pageId = ? ORDER BY position ASC");
			try
			{
				statement.setString(1, pageId);
				ResultSet resultSet = statement.executeQuery();
				try
				{
					List<String> cssIds = new ArrayList<String>();

					while (resultSet.next())
						cssIds.add(resultSet.getString("cssId"));				

					return cssIds;
				}
				finally
				{
					resultSet.close();				
				}				
			}
			finally
			{
				statement.close();				
			}
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}
	
	public List<IChannelChild> getChannelsChildren(String parentChannelIds, boolean hidePages, boolean hidePageTemplates, IResource resource, Locale locale, ITransaction transaction) throws PortalException
	{
		ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
		Connection connection = daoTransactionJdbc.getConnection();		
		
		if (!(hidePages && hidePageTemplates))
		{
			String hiddenCriteria = "";
			if (hidePages)
				hiddenCriteria = "and isTemplate <> 0 ";
			else if (hidePageTemplates)
				hiddenCriteria = "and isTemplate <> 1 ";

			String query = "select pageId, name, channelId, isTemplate, hidden, position from lum_Page where channelId IN (" + parentChannelIds + ") " + hiddenCriteria;
			try
			{
				PreparedStatement statement = connection.prepareStatement(query);
				try
				{
					ResultSet resultSet = statement.executeQuery();
					try
					{
						// put results in a list
						List<IChannelChild> children = new ArrayList<IChannelChild>(); 
						while (resultSet.next())
						{
							GenericChannelChild page = new GenericChannelChild();
							page.setId(resultSet.getString("pageId"));
							page.setLocalizedName(ManagerFactory.getLocalizationManager().localize(resultSet.getString("name"), resource, locale));
							page.setChannelId(resultSet.getString("channelId"));
							page.setTemplate(resultSet.getInt("isTemplate") > 0);
							page.setHidden(resultSet.getInt("hidden") > 0);
							page.setPosition(resultSet.getInt("position"));
							children.add(page);
						}
						
						// order the list
						Collections.sort(children);
						
						return children;
					}
					finally
					{
						resultSet.close();						
					}
				}
				finally
				{
					statement.close();					
				}				
			}
			catch(SQLException e)
			{
				throw new UnexpectedException(e);
			}
		}
		else
			return Collections.<IChannelChild>emptyList();
	}
	
	public List<IChannelChild> getChildrenData(String channelId, int hidePages, int hidePageTemplates, IResource resource, Locale locale, ITransaction transaction) throws DaoException, PortalException
	{
		try
		{
			if (hidePages != IChannelChildProvider.HIDE_TYPE_ALWAYS || hidePageTemplates != IChannelChildProvider.HIDE_TYPE_ALWAYS)
			{
				String hiddenCriteria = "";
				String hiddenCriteriaPages = "";
				String hiddenCriteriaPageTemplates = "";
				
				if (hidePages == IChannelChildProvider.HIDE_TYPE_NEVER)
					hiddenCriteriaPages = " (isTemplate = 0) ";
				else if (hidePages == IChannelChildProvider.HIDE_TYPE_IF_HIDDEN_SPECIFIED)
					hiddenCriteriaPages = " (isTemplate = 0 and hidden = 0) ";
				
				if (hidePageTemplates == IChannelChildProvider.HIDE_TYPE_NEVER)
					hiddenCriteriaPageTemplates = " (isTemplate = 1) ";
				else if (hidePageTemplates == IChannelChildProvider.HIDE_TYPE_IF_HIDDEN_SPECIFIED)
					hiddenCriteriaPageTemplates = " (isTemplate = 1 and hidden = 0) ";
				
				if(hiddenCriteriaPages.length() != 0 && hiddenCriteriaPageTemplates.length() != 0)
					hiddenCriteria = " and (" + hiddenCriteriaPages + " or " + hiddenCriteriaPageTemplates + ") ";
				else
					hiddenCriteria = " and " + hiddenCriteriaPages + hiddenCriteriaPageTemplates;
				
				ITransactionJdbc daoTransactionJdbc = (ITransactionJdbc) transaction;
				Connection connection = daoTransactionJdbc.getConnection();

				String query = "select pageId, name, channelId, isTemplate, hidden, position from lum_Page where channelId = ?" + hiddenCriteria;
				PreparedStatement statement = connection.prepareStatement(query);
				try
				{
					statement.setString(1, channelId);
					ResultSet resultSet = statement.executeQuery();
					try
					{
						ILocalizationManager localizationManager = ManagerFactory.getLocalizationManager();

						// put results in a list
						List<IChannelChild> children = new ArrayList<IChannelChild>(); 
						while (resultSet.next())
						{
							GenericChannelChild page = new GenericChannelChild();
							page.setId(resultSet.getString("pageId"));
							page.setLocalizedName(localizationManager.localize(resultSet.getString("name"), resource, locale));
							page.setChannelId(resultSet.getString("channelId"));
							page.setTemplate(resultSet.getInt("isTemplate") > 0);
							page.setHidden(resultSet.getInt("hidden") > 0);
							page.setPosition(resultSet.getInt("position"));
							children.add(page);
						}
						
						// order the list
						Collections.sort(children);
						
						return children;
					}
					finally
					{
						resultSet.close();											
					}
				}
				finally
				{
					statement.close();					
				}
			}
			else
				return Collections.<IChannelChild>emptyList();
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}	
}
